package com.cskaoyan.javase.oop3._2inner._6lambda._1basic;

import com.sun.xml.internal.ws.api.message.MessageWritable;

/**
 * Lambda表达式的语法是:
 *   () -> {}
 * 以上Lambda表达式的语法是可以继续简化的
 * 当然Lambda表达式简化的前提是:
 *      Lambda表达式实现的是功能接口的子类对象,这意味着它只能实现一个抽象方法
 * Lambda表达式简化的原则是:
 *      简化不能带来歧义或者导致Lambda表达式语意不明
 *
 * 1."()",表示功能接口中那个必须要子类实现的抽象方法的形参列表.
 *      所以()中的形参数据类型即便不写,也是不会变化的
 *      那么干脆就不要写了
 *      但是形参名不能取消,因为在方法体中可能会使用形参.
 *      特殊的,如果是一个单参数抽象方法,那么()可以省略,直接写形参名.
 *      但如果是一个无参的方法,小括号是不能省略的
 *          小括号在无参的情况下,必须存在.
 *
 * 2."{}",表示重写功能接口中抽象方法的重写方法体
 *      当重写方法体的语句仅有一条语句时,那么可以省略大括号.
 *      特殊的,当这一条语句就是方法的返回值语句时,那么{}和return一起省略.
 *
 * 3.实际上在多数情况下，都不太可能一句话把方法体写完。
 *      多数情况下，Lambda表达式的抽象方法实现都会很复杂，那这样Lambda表达式就会写的很复杂，这就很难受了。
 *      而Lambda表达式，本质上就是重写了一个抽象方法的子类对象，
 *      所以Java允许Lambda表达式的抽象方法的实现可以直接指向一个已经存在的方法，而不是自己书写实现。
 *      这种语法在Java中称之为"方法引用"！
 *
 * 当然在使用方法引用之前,什么样的方法,可以当成Lambda表达式中抽象方法的实现?
 * 抽象方法:
 *      返回值类型 方法名(形参列表);
 *  1.访问权限修饰符和static之类的修饰符,实际没有多大影响.但是肯定需要访问权限.
 *  2.返回值类型,应该保持一致
 *      注: 但是如果抽象方法返回一个父类引用类型,那么这个已实现的方法可以返回子类类型.
 *  3.方法名是什么不重要.
 *  4.形参列表.必须保持一致,数据类型,位置必须严格对应.但是形参名无所谓
 *  5.方法体.无所谓,自己重写即可.
 *
 * 方法引用的语法,有两种形式:
 *      1.不省略"->"的写法
 *      (形参列表) -> 已实现的方法(形参列表);
 *      在调用这个已实现方法的时候:
 *          如果这个方法是静态方法,用类名点调用
 *          如果是个成员方法,用对象名点调用
 *          上述语法中的形参列表必须严格保持一致,表示将抽象方法中形参传递给已实现的方法
 *
 *     2.省略"->"的写法
 *     方法的归属者::方法名;
 *     以上就是一个Lambda表达式
 *
 *     方法的归属者:
 *          static方法属于类,写类名
 *          非static方法属于对象,写对象名
 *
 *
 * @since 10:05
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        INoReturnTwoParam ip1 = (a, b) -> {
            System.out.println(a + " + " + b + " = " + (a + b));
        };
        ip1.test(1, 1);

        INoReturnOneParam ip2 = a -> {
            System.out.println("你输入的参数是:" + a);
        };

        INoReturnNoParam ip3 = () -> System.out.println("hello world!");
        ip3.test();

        IHasReturnNoParam ip4 = () -> 0;

        IHasReturnTwoParam ip5 = (a, b) -> a + b;
        System.out.println(ip5.test(1, 1));

        INoReturnNoParam ip6 = () -> new Demo().myTest2();
        ip6.test();

        IHasReturnNoParam ip7 = () -> myTest1();
        System.out.println(ip7.test());

        IHasReturnTwoParam ip8 = (a, b) -> new Demo().myTest3(a, b);
        System.out.println(ip8.test(1, 1));

        IA Ia = Demo::myTest4;
        System.out.println(Ia.test());

        Test t = new Test();
        IB ib = t::myTest;
        System.out.println(ib.test(10, 10));


    }

    public static int myTest1() {
        System.out.println("hello world!");
        System.out.println("hello world!");
        System.out.println("hello world!");
        return 0;
    }

    public void myTest2() {
        System.out.println("6666");
        System.out.println("6666");
        System.out.println("6666");
        System.out.println("6666");
    }

    public int myTest3(int num1, int num2) {
        System.out.println("777");
        System.out.println("777");
        System.out.println("777");
        return num1 + num2;
    }

    public static Demo myTest4() {
        System.out.println("888");
        System.out.println("888");
        System.out.println("888");
        return new Demo();
    }
}

class Test {
    public Test myTest(int num, int num2) {
        System.out.println(num + num2);
        System.out.println(num - num2);
        System.out.println(num * num2);
        System.out.println(num / num2);
        return new Test();
    }
}

interface IB {
    Object test(int a, int b);
}

interface IA {
    Object test();
}

//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}